import type { PluginOption } from 'vite'

import type {
    ApplicationPluginOptions,
    CommonPluginOptions,
    ConditionPlugin,
    LibraryPluginOptions
} from '../typing'

import viteVueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'
import viteVue from '@vitejs/plugin-vue'
import viteVueJsx from '@vitejs/plugin-vue-jsx'
import { visualizer as viteVisualizerPlugin } from 'rollup-plugin-visualizer'
import viteCompressPlugin from 'vite-plugin-compression'
import viteDtsPlugin from 'vite-plugin-dts'
import { createHtmlPlugin as viteHtmlPlugin } from 'vite-plugin-html'
import { VitePWA } from 'vite-plugin-pwa'
import viteVueDevTools from 'vite-plugin-vue-devtools'

import { viteArchiverPlugin } from './archiver'
import { viteExtraAppConfigPlugin } from './extra-app-config'
import { viteImportMapPlugin } from './importmap'
import { viteInjectAppLoadingPlugin } from './inject-app-loading'
import { viteMetadataPlugin } from './inject-metadata'
import { viteLicensePlugin } from './license'
import { viteNitroMockPlugin } from './nitro-mock'
import { vitePrintPlugin } from './print'
import { viteVxeTableImportsPlugin } from './vxe-table'

/**
 * 获取条件成立的 vite 插件
 * @param conditionPlugins
 */
async function loadConditionPlugins(conditionPlugins: ConditionPlugin[]) {
    const plugins: PluginOption[] = []
    for (const conditionPlugin of conditionPlugins) {
        if (conditionPlugin.condition) {
            const realPlugins = await conditionPlugin.plugins()
            plugins.push(...realPlugins)
        }
    }
    return plugins.flat()
}

/**
 * 根据条件获取通用的vite插件
 */
async function loadCommonPlugins(options: CommonPluginOptions): Promise<ConditionPlugin[]> {
    const { devtools, injectMetadata, isBuild, visualizer } = options
    return [
        {
            condition: true,
            plugins: () => [
                viteVue({
                    script: {
                        defineModel: true
                        // propsDestructure: true,
                    }
                }),
                viteVueJsx()
            ]
        },

        {
            condition: !isBuild && devtools,
            plugins: () => [viteVueDevTools()]
        },
        {
            condition: injectMetadata,
            plugins: async () => [await viteMetadataPlugin()]
        },
        {
            condition: isBuild && !!visualizer,
            plugins: () => [<PluginOption>viteVisualizerPlugin({
                    filename: './node_modules/.cache/visualizer/stats.html',
                    gzipSize: true,
                    open: true
                })]
        }
    ]
}

/**
 * 根据条件获取应用类型的vite插件
 */
async function loadApplicationPlugins(options: ApplicationPluginOptions): Promise<PluginOption[]> {
    // 单独取，否则commonOptions拿不到
    const isBuild = options.isBuild
    const env = options.env

    const {
        archiver,
        archiverPluginOptions,
        compress,
        compressTypes,
        extraAppConfig,
        html,
        i18n,
        importmap,
        importmapOptions,
        injectAppLoading,
        license,
        nitroMock,
        nitroMockOptions,
        print,
        printInfoMap,
        pwa,
        pwaOptions,
        vxeTableLazyImport,
        ...commonOptions
    } = options

    const commonPlugins = await loadCommonPlugins(commonOptions)

    return await loadConditionPlugins([
        ...commonPlugins,
        {
            condition: i18n,
            plugins: async () => {
                return [
                    viteVueI18nPlugin({
                        compositionOnly: true,
                        fullInstall: true,
                        runtimeOnly: true
                    })
                ]
            }
        },
        {
            condition: print,
            plugins: async () => {
                return [await vitePrintPlugin({ infoMap: printInfoMap })]
            }
        },
        {
            condition: vxeTableLazyImport,
            plugins: async () => {
                return [await viteVxeTableImportsPlugin()]
            }
        },
        {
            condition: nitroMock,
            plugins: async () => {
                return [await viteNitroMockPlugin(nitroMockOptions)]
            }
        },

        {
            condition: injectAppLoading,
            plugins: async () => [await viteInjectAppLoadingPlugin(!!isBuild, env)]
        },
        {
            condition: license,
            plugins: async () => [await viteLicensePlugin()]
        },
        {
            condition: pwa,
            plugins: () =>
                VitePWA({
                    injectRegister: false,
                    workbox: {
                        globPatterns: []
                    },
                    ...pwaOptions,
                    manifest: {
                        display: 'standalone',
                        start_url: '/',
                        theme_color: '#ffffff',
                        ...pwaOptions?.manifest
                    }
                })
        },
        {
            condition: isBuild && !!compress,
            plugins: () => {
                const compressPlugins: PluginOption[] = []
                if (compressTypes?.includes('brotli')) {
                    compressPlugins.push(
                        viteCompressPlugin({ deleteOriginFile: false, ext: '.br' })
                    )
                }
                if (compressTypes?.includes('gzip')) {
                    compressPlugins.push(
                        viteCompressPlugin({ deleteOriginFile: false, ext: '.gz' })
                    )
                }
                return compressPlugins
            }
        },
        {
            condition: !!html,
            plugins: () => [viteHtmlPlugin({ minify: true })]
        },
        {
            condition: isBuild && importmap,
            plugins: () => {
                return [viteImportMapPlugin(importmapOptions)]
            }
        },
        {
            condition: isBuild && extraAppConfig,
            plugins: async () => [
                await viteExtraAppConfigPlugin({ isBuild: true, root: process.cwd() })
            ]
        },
        {
            condition: archiver,
            plugins: async () => {
                return [await viteArchiverPlugin(archiverPluginOptions)]
            }
        }
    ])
}

/**
 * 根据条件获取库类型的vite插件
 */
async function loadLibraryPlugins(options: LibraryPluginOptions): Promise<PluginOption[]> {
    // 单独取，否则commonOptions拿不到
    const isBuild = options.isBuild
    const { dts, ...commonOptions } = options
    const commonPlugins = await loadCommonPlugins(commonOptions)
    return await loadConditionPlugins([
        ...commonPlugins,
        {
            condition: isBuild && !!dts,
            plugins: () => [viteDtsPlugin({ logLevel: 'error' })]
        }
    ])
}

export {
    loadApplicationPlugins,
    loadLibraryPlugins,
    viteArchiverPlugin,
    viteCompressPlugin,
    viteDtsPlugin,
    viteHtmlPlugin,
    viteVisualizerPlugin,
    viteVxeTableImportsPlugin
}
